#include "SpriteInstanceList.h"

SpriteInstanceList::SpriteInstanceList() :
    m_spriteInstanceIndexCounter(0),
    m_currentCtx(*(CurrentContext::get_instance())),
    m_viewport(*(Viewport::get_instance()))
{

}

bool SpriteInstanceList::add(uint imgId, uint spriteId, SDL_Rect rect, bool visible, bool solid)
{
    if( !visible ) {
        cout << "ADDED INVISIBLE SPRITE" << endl;
    }
    list<SpriteInstance> ::reverse_iterator i;
    SpriteInstance newItem;
    newItem.m_imgId = imgId;
    newItem.m_spriteId = spriteId;
    newItem.m_visible = visible;
    newItem.m_solid = solid;
    newItem.m_spriteInstanceId = m_spriteInstanceIndexCounter++;
    newItem.m_posRect.m_rect = rect;
    newItem.m_posRect.m_x2 = rect.x + rect.w;
    newItem.m_posRect.m_y2 = rect.y + rect.h;
    m_mutex.lock();

    for(i = m_spriteInstances.rbegin(); i != m_spriteInstances.rend(); i++) {
        if(newItem.overLaps(*i)) {
            break;
        }
    }

    if (i == m_spriteInstances.rbegin()) {
        m_spriteInstances.push_back(newItem);
    } else {
        m_spriteInstances.insert(i.base(), newItem);
    }

    m_currentCtx.setActiveSpriteInfo(newItem.m_spriteInstanceId,
        newItem.m_imgId, newItem.m_spriteId, newItem.m_posRect.m_rect);
    if (Debug::test(DEBUG_ADD_REMOVE)) {
        cout << "new sprite instance added at " << newItem.m_posRect.m_rect.x << " " << newItem.m_posRect.m_x2 << " " <<
            newItem.m_posRect.m_rect.y << " " << newItem.m_posRect.m_y2 << endl;
    }


    m_mutex.unlock();
    return true;
}

bool SpriteInstanceList::hasXY(int x, int y)
{
    m_mutex.lock();
    list<SpriteInstance> ::reverse_iterator r;
    for(r = m_spriteInstances.rbegin(); r != m_spriteInstances.rend(); r++) {
        if( r->hasXY(x, y)) {
            return true;
        }
    }
    m_mutex.unlock();
    return false;
}

void SpriteInstanceList::draw(SDL_Surface *layer)
{
    lock();
    list<SpriteInstance> ::iterator i;
    for (i = m_spriteInstances.begin(); i != m_spriteInstances.end(); i++) {
        if (!i->m_visible) {
            continue;
        }

        ImageList &img = *(ImageList::get_instance());
        ImageListItem &image = img[i->m_imgId];

        Image_Wrapper &src_img = *(image.m_pImg);
        SpriteListItem &sprite = image.m_spriteList[i->m_spriteId];
        if (Debug::test(DEBUG_DRAW)) {
            cout << "Drawing sprite at: " << i->m_posRect.m_rect.x << " " << i->m_posRect.m_rect.y
                << " " << i->m_posRect.m_rect.w << " " << i->m_posRect.m_rect.h << endl;
        }
        SDL_Rect r = i->m_posRect.m_rect;
        r.x -= m_viewport.wx;
        r.y -= m_viewport.wy;
        SDL_BlitSurface(src_img.image, &sprite.m_rect, layer, &r);
    }
    unlock();
}

bool SpriteInstanceList::makeSpriteAtXYActive(int x, int y)
{
    m_mutex.lock();
    list<SpriteInstance> ::reverse_iterator i;
    for(i = m_spriteInstances.rbegin(); i != m_spriteInstances.rend(); i++) {
        if( i->hasXY(x, y)) {
            m_currentCtx.setActiveSpriteInfo(i->m_spriteInstanceId, i->m_imgId,
                i->m_spriteId, i->m_posRect.m_rect);
//                cout << "SpriteInstanceList::makeSpriteAtXYActive made sprite at " << x << " " << y << " active" << endl;
            m_mutex.unlock();
            return true;
        }
    }
    m_mutex.unlock();
    return false;
}

void SpriteInstanceList::moveActiveSpritebyXY(Sint16 x, Sint16 y)
{
    uint activeSpriteInstanceIndex;
    uint activeSpriteInstanceImageIndex;
    uint activeSpriteInstanceSpriteIndex;
    SDL_Rect activeSpriteRect;
    if(!m_currentCtx.getActiveSpriteInfo(activeSpriteInstanceIndex,
                activeSpriteInstanceImageIndex, activeSpriteInstanceSpriteIndex,
                activeSpriteRect)) {
        return;
    }

    m_mutex.lock();
    list<SpriteInstance> ::reverse_iterator i;
    for(i = m_spriteInstances.rbegin(); i != m_spriteInstances.rend(); i++) {
        if (i->m_spriteInstanceId == activeSpriteInstanceIndex) {
            i->movebyXY(x, y);
            m_currentCtx.setActiveSpriteInfo(i->m_spriteInstanceId, i->m_imgId,
                i->m_spriteId, i->m_posRect.m_rect);
            break;
        }
    }
    m_mutex.unlock();
}

/*
bool SpriteList::find(uint spriteId, uint &imgId, RectInfo &rect)
{
    list<SpriteListItem>::iterator i;
    m_mutex.lock();
   for(i=m_sprites.begin(); i != m_sprites.end(); ++i) {
       if(i->m_spriteId == spriteId) {
           imgId = i->m_imgId;
           spriteId = i->m_spriteId;
           m_mutex.unlock();
       }
   }
   m_mutex.unlock();
   return true;

}
*/

bool SpriteInstanceList::activeSpriteBringToFront()
{
    if (Debug::test(DEBUG_INFO)) {
        cout << "bool SpriteInstanceList::ActiveSpriteBringToFront()" << endl;
    }
    uint activeSpriteInstanceIndex;
    uint activeSpriteInstanceImageIndex;
    uint activeSpriteInstanceSpriteIndex;
    SDL_Rect activeSpriteRect;
    if(!m_currentCtx.getActiveSpriteInfo(activeSpriteInstanceIndex,
                activeSpriteInstanceImageIndex, activeSpriteInstanceSpriteIndex,
                activeSpriteRect)) {
        return false;
    }

    if (Debug::test(DEBUG_DRAW)) {
        cout << "ActiveSpriteBringToFront() : active sprite found" << endl;
    }

    m_mutex.lock();
    list<SpriteInstance> ::iterator i;
    for (i = m_spriteInstances.begin(); i != m_spriteInstances.end(); i++) {
        if (i->m_spriteInstanceId == activeSpriteInstanceIndex) {
            break;
        }
    }

    if (i == m_spriteInstances.end()) {
        m_mutex.unlock();
        return false;
    }

    SpriteInstance *curSprite = &(*i);

    if (Debug::test(DEBUG_DRAW)) {
        cout << "ActiveSpriteBringToFront() : " << curSprite->m_spriteInstanceId <<  " to be brought to front " << endl;
    }



    for (i++; i != m_spriteInstances.end(); i++) {
        if (Debug::test(DEBUG_DRAW)) {
            cout << "trying to find a overlapping sprite" << endl;
        }
         if (i->overLaps(curSprite->m_posRect)) {

             if (Debug::test(DEBUG_DRAW)) {
                 cout << "ActiveSpriteBringToFront() : " << i->m_spriteInstanceId <<  " to be sent to back " << endl;
             }

             SpriteInstance temp = *curSprite;
             *curSprite = *i;
             *i = temp;

             m_mutex.unlock();
             return true;
        }
    }

    m_mutex.unlock();
    return false;
}

bool SpriteInstanceList::activeSpriteSendToBack()
{
    if (Debug::test(DEBUG_INFO)) {
        cout << "bool SpriteInstanceList::ActiveSpriteSendToBack()" << endl;
    }
    uint activeSpriteInstanceIndex;
    uint activeSpriteInstanceImageIndex;
    uint activeSpriteInstanceSpriteIndex;
    SDL_Rect activeSpriteRect;
    if(!m_currentCtx.getActiveSpriteInfo(activeSpriteInstanceIndex,
                activeSpriteInstanceImageIndex, activeSpriteInstanceSpriteIndex,
                activeSpriteRect)) {
        return false;
    }

    if (Debug::test(DEBUG_DRAW)) {
        cout << "ActiveSpriteSendToBack() : active sprite found" << endl;
    }

    m_mutex.lock();
    list<SpriteInstance> ::reverse_iterator i;
    for (i = m_spriteInstances.rbegin(); i != m_spriteInstances.rend(); i++) {
        if (i->m_spriteInstanceId == activeSpriteInstanceIndex) {
            break;
        }
    }

    if (i == m_spriteInstances.rend()) {
        m_mutex.unlock();
        return false;
    }

    SpriteInstance *curSprite = &(*i);

    if (Debug::test(DEBUG_DRAW)) {
        cout << "ActiveSpriteSendToBack() : " << curSprite->m_spriteInstanceId <<  " to be sent to back" << endl;
    }



    for (i++; i != m_spriteInstances.rend(); i++) {
        if (Debug::test(DEBUG_DRAW)) {
            cout << "trying to find a overlapping sprite" << endl;
        }
        if (i->overLaps(curSprite->m_posRect)) {
            if (Debug::test(DEBUG_DRAW)) {
                 cout << "ActiveSpriteSendToBack() : " << i->m_spriteInstanceId <<  " to be brought to front " << endl;
            }

            SpriteInstance temp = *curSprite;
            *curSprite = *i;
            *i = temp;

            m_mutex.unlock();
            return true;
        }
    }

    m_mutex.unlock();
    return false;
}

bool SpriteInstanceList::activeSpriteToggleVisible()
{
    if (Debug::test(DEBUG_INFO)) {
        cout << "bool SpriteInstanceList::ActiveSpriteToggleSolid()" << endl;
    }
    uint activeSpriteInstanceIndex;
    uint activeSpriteInstanceImageIndex;
    uint activeSpriteInstanceSpriteIndex;
    SDL_Rect activeSpriteRect;
    if(!m_currentCtx.getActiveSpriteInfo(activeSpriteInstanceIndex,
                activeSpriteInstanceImageIndex, activeSpriteInstanceSpriteIndex,
                activeSpriteRect)) {
        return false;
    }

    if (Debug::test(DEBUG_INFO)) {
        cout << "ActiveSpriteToggleSolid() : active sprite found" << endl;
    }

    m_mutex.lock();
    list<SpriteInstance> ::reverse_iterator i;
    for (i = m_spriteInstances.rbegin(); i != m_spriteInstances.rend(); i++) {
        if (i->m_spriteInstanceId == activeSpriteInstanceIndex) {
            i->toggleVisible();
            break;
        }
    }

    if (i == m_spriteInstances.rend()) {
        m_mutex.unlock();
        return false;
    }
    m_mutex.unlock();
    return true;
}

bool SpriteInstanceList::activeSpriteToggleSolid()
{
    if (Debug::test(DEBUG_INFO)) {
        cout << "bool SpriteInstanceList::ActiveSpriteToggleSolid()" << endl;
    }
    uint activeSpriteInstanceIndex;
    uint activeSpriteInstanceImageIndex;
    uint activeSpriteInstanceSpriteIndex;
    SDL_Rect activeSpriteRect;
    if(!m_currentCtx.getActiveSpriteInfo(activeSpriteInstanceIndex,
                activeSpriteInstanceImageIndex, activeSpriteInstanceSpriteIndex,
                activeSpriteRect)) {
        return false;
    }

    if (Debug::test(DEBUG_INFO)) {
        cout << "ActiveSpriteToggleSolid() : active sprite found" << endl;
    }

    m_mutex.lock();
    list<SpriteInstance> ::reverse_iterator i;
    for (i = m_spriteInstances.rbegin(); i != m_spriteInstances.rend(); i++) {
        if (i->m_spriteInstanceId == activeSpriteInstanceIndex) {
            i->toggleSolid();
            break;
        }
    }

    if (i == m_spriteInstances.rend()) {
        m_mutex.unlock();
        return false;
    }
    m_mutex.unlock();
    return true;
}

bool SpriteInstanceList::activeSpriteDelete()
{
    if (Debug::test(DEBUG_INFO)) {
        cout << "bool SpriteInstanceList::ActiveSpriteToggleSolid()" << endl;
    }
    uint activeSpriteInstanceIndex;
    uint activeSpriteInstanceImageIndex;
    uint activeSpriteInstanceSpriteIndex;
    SDL_Rect activeSpriteRect;
    if(!m_currentCtx.getActiveSpriteInfo(activeSpriteInstanceIndex,
                activeSpriteInstanceImageIndex, activeSpriteInstanceSpriteIndex,
                activeSpriteRect)) {
        return false;
    }

    if (Debug::test(DEBUG_INFO)) {
        cout << "ActiveSpriteToggleSolid() : active sprite found" << endl;
    }

    m_mutex.lock();
    list<SpriteInstance> ::iterator i;
    for (i = m_spriteInstances.begin(); i != m_spriteInstances.end(); i++) {
        if (i->m_spriteInstanceId == activeSpriteInstanceIndex) {
            m_spriteInstances.erase(i);
            break;
        }
    }

    if (i == m_spriteInstances.end()) {
        m_mutex.unlock();
        return false;
    }
    m_mutex.unlock();
    return true;
}

SpriteInstanceList::~SpriteInstanceList()
{
    m_spriteInstances.clear();
}
